// 设置节点唯一标识
let key_id = 0

function diff(oldTree, newTree) {
    let patchs = {};
    let index = 0; //开始比较的层级
    walk(oldTree, newTree, index, patchs);
    return patchs;
}

function diffChildren(oldChildren, newChildren, index, patches) {

    // 比较老的第一个和新的第一个
    oldChildren.forEach((child, idx) => {
        // 记得索引得改
        // Index 每次传递给walk时，index是递增的，所有节点都基于一个序号实现，因此需要维护一个全局Index
        walk(child, newChildren[idx], ++key_id, patches);
    })
}

function diffAttrs(oldAttrs, newAttrs) {
    let path = {};
    //判断新旧属性是否一致
    for (let key in oldAttrs) {
        if (oldAttrs[key] !== newAttrs[key]) {
            path[key] = newAttrs[key];
        }
    }

    //判断是否新增属性
    for (let key in newAttrs) {
        if (!oldAttrs.hasOwnProperty(key)) {
            path[key] = newAttrs[key];
        }
    }
    return path;
}

function isString(node) {
    return Object.prototype.toString.call(node).replace(/\[object\s|\]/g, '')
}

function walk(oldTree, newTree, index, patches) {
    let currentPatch = [];//每个元素都有一个补丁对象

    if (!newTree) {
        currentPatch.push({type: 'REMOVE', index});
    }

    if (isString(oldTree) && isString(newTree)) {
        // 判断文本是否一致
        if (oldTree !== newTree) {
            currentPatch.push({type: 'TEXT', text: newTree});
        }
    } else if (oldTree.type === newTree.type) {
        //比较属性是否有更改
        let attrs = diffAttrs(oldTree.props, newTree.props);
        if (Object.keys(attrs).length) {
            currentPatch.push({type: 'ATTRS', attrs});
        }
        // 如果有儿子节点，遍历子节点
        diffChildren(oldTree.children, newTree.children, index, patches);
    } else {
        // 节点类型不同的时候，直接替换
        currentPatch.push({type: 'REPLACE', newTree});
    }

    // 当前元素有补丁的情况下，将元素和补丁对应起来，放到大补丁包中
    if (currentPatch.length) {
        patches[index] = currentPatch;
    }
}

/**
 * 规则：当节点类型相同时，比较属性是否相同 产生一个属性包
 *  新的DOM不存在标志位当前节点删除了
 *  节点类型不相同直接采用替换模式（新的替换旧的）
 *  文本变化
 */
export default diff;